import socket,sqlite3,subprocess,re,json,threading
import threading
import time
import sqlite3,json
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')))
import backend.DID.DID_interface as did_interface
import backend.P2P.device_management as device_mag
# import backend.DID.DIDSocket as DIDSocket
# from backend.DID.DIDSocket1 import DIDSocket
from backend.DID.DIDsocket import DIDSocket


#单人聊天类
class Private_chat ():
    server_started = False  # 类变量，保证只启动一个 server
    resend_thread_started = False
    def __init__(self,socketio=None,ip=None, id=None ,server_socket=None):
        self.socketio=socketio
        self.ip=ip
        self.friend_id=id
        self.connected = False  
        self.messages = []  # 改成列表，存多条消息,避免一秒钟发多条消息
        if not Private_chat.server_started:  # 启动服务端监听线程，只启动一次
            Private_chat.server_started = True
            threading.Thread(target=self.server).start()
        if not Private_chat.resend_thread_started:
            Private_chat.resend_thread_started = True
            threading.Thread(target=self.auto_resend_loop).start()
    def server(self):#服务端
        # self.server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#ipv4,TCP
        # self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 允许重用端口
        # self.server_socket.bind(('0.0.0.0',3456))#绑定ip和端口号,bind() 方法只接受一个参数，需要的是一个元组 (IP, 端口号)
        current_id=self.get_userid()
        print(current_id)
        self.did_socket=DIDSocket(current_id)
        self.did_socket.listen(3456)
        print("服务器已启动，等待客户端连接...")
        while True:
                result=self.did_socket.accept()
                if result is None:
                    time.sleep(1)  # 防止空转
                    continue
                client_socket, client_address = result
                print(f'已成功连接 {client_address}')
                client_thread = threading.Thread(target=self.handle_client, args=(client_socket,), daemon=True)
                client_thread.start()
    def handle_client(self, client_socket):
        while True:
            try:
                data=self.did_socket.recv(client_socket)
                data=self.did_socket.recv(client_socket)
                #!!!!!!!!!
                #使用did-recv or client_socket
                print(f'data{data}')
                if not data:
                    print("连接断开")
                    break
                try:
                    # message_obj = json.loads(data)
                    message_obj = data
                    friend_id = message_obj['id']
                    friend_name = message_obj['name']
                    message = message_obj['message']
                    timestamp=message_obj["timestamp"]
                except Exception as e:
                    print(f"JSON解析失败：{e}")


                print(message)
                # print("界面当前聊天对象 ID:", self.friend_id)
                # print("接收到的消息发送者 ID:", friend_id)
                # self.messages.append(message)
                response = f"服务端收到消息:'{message}'"
                self.save_message(friend_id,friend_id, message, 1,timestamp)
                message_request={
                    "action": "loadMessage",    
                    "friend_id":friend_id,
                    "friend_name":friend_name,
                    "message":message,
                    "timestamp":timestamp
                }
                self.socketio.emit("client",message_request)
                print("已经接收到消息")
                try:
                    self.did_socket.send(client_socket,response)
                except (ConnectionResetError, ConnectionAbortedError) as e:
                    print(f"客户端已断开，发送失败：{e}")
                    break
            except ConnectionResetError:
                print('连接被重置')
                break
            except Exception as e:
                print(f"接收失败：{e}")
                break
        #server_socket.close()
        # client_socket.close()
    def client(self,message,id,timestamp,name_):
        print("client")
        if id.startswith("did"):
            print("是以 'did' 开头的")
        else:
            device_mag.enable_device(message,self.socketio,id,timestamp,name_)
            return 1
        print(message)
        # print(id)
        # print(timestamp)
        if not message:
            print("输入为空，忽略")
            return 
        with sqlite3.connect("p2p.db", check_same_thread=False,timeout=10) as connect:
            cursor=connect.cursor()
            print(id)
            cursor.execute("select ip,host_id from friends where id=?",(id,))
            friend=cursor.fetchone()
            if friend:
                print(friend)
            else:
                print("该好友不存在")
                return 0
            friend_ip=friend[0]
            host_id=friend[1]
            #如果存在绑定主机id，则使用绑定主机id
            # if host_id!=0:
            #     print("使用hostid")
            #     print(host_id)
            #     id=host_id
            cursor.execute("SELECT id,name  FROM current_user")
            user = cursor.fetchone()
            if friend:
                user_id = user[0]
                name=user[1]
            data = {
            "id": user_id,
            "name":name,
            "message": message,
            "timestamp":timestamp
                }
            # connect.close()
            try:
                current_id=self.get_userid()
                print(id)
                print(current_id)
                print(message)
                did_socket=DIDSocket(current_id)
                conn_socket=did_socket.connect(id,3456,friend_ip)
                if conn_socket is None:
                    raise ConnectionError("连接失败")  # 抛出异常，程序会跳到 except 区块
                result=did_socket.send(conn_socket,data)
                print(f"send的结果为：{result}")
                print("准备接收 response")
                # response = did_socket.recv(conn_socket)
                print("接收到 response")
                if result:
                    # print(f'发送成功：{response}')
                    print("发送成功")
                    self.save_message(id, user_id, message, 1,timestamp)  # 已发送
                else:
                    print(f"不在线，存为离线消息")
                    raise ConnectionError("send失败")
            except Exception as e:
                print("发送失败", e)
                self.save_message(id, user_id, message, 0,timestamp)  # 已发送
            finally:
                try:
                    did_socket.close_connection(conn_socket)
                except:
                    pass
            return message
        with sqlite3.connect("p2p.db", check_same_thread=False,timeout=10) as connect:
            cursor=connect.cursor()
            print(id)
            cursor.execute("select ip,host_id from friends where id=?",(id,))
            friend=cursor.fetchone()
            if friend:
                print(friend)
            else:
                print("该好友不存在")
                return 0
            friend_ip=friend[0]
            host_id=friend[1]
            #如果存在绑定主机id，则使用绑定主机id
            # if host_id!=0:
            #     print("使用hostid")
            #     print(host_id)
            #     id=host_id
            cursor.execute("SELECT id,name  FROM current_user")
            user = cursor.fetchone()
            if friend:
                user_id = user[0]
                name=user[1]
            data = {
            "id": user_id,
            "name":name,
            "message": message,
            "timestamp":timestamp
                }
            # connect.close()
            try:
                current_id=self.get_userid()
                print(id)
                print(current_id)
                print(message)
                did_socket=DIDSocket(current_id)
                conn_socket=did_socket.connect(id,3456,friend_ip)
                if conn_socket is None:
                    raise ConnectionError("连接失败")  # 抛出异常，程序会跳到 except 区块
                result=did_socket.send(conn_socket,data)
                print(f"send的结果为：{result}")
                print("准备接收 response")
                # response = did_socket.recv(conn_socket)
                print("接收到 response")
                if result:
                    # print(f'发送成功：{response}')
                    print("发送成功")
                    self.save_message(id, user_id, message, 1,timestamp)  # 已发送
                else:
                    print(f"不在线，存为离线消息")
                    raise ConnectionError("send失败")
            except Exception as e:
                print("发送失败", e)
                self.save_message(id, user_id, message, 0,timestamp)  # 已发送
            finally:
                try:
                    did_socket.close_connection(conn_socket)
                except:
                    pass
            return message
    # def GetMessage(self):
    #     print("get_message")
    #     if self.messages:
    #         return self.messages.copy()#避免清空时出错
    #     else:
    #         return []#返回空列表
    def save_message(self,friend_id,sent,message,is_sent,timestamp):
        info=self.get_device_info()
        # print(f"info{info}")
        conn = sqlite3.connect("p2p.db",check_same_thread=False, timeout=10)
        cursor = conn.cursor()
        cursor.execute("select id from current_user")
        current_id=cursor.fetchone()
        current_id=current_id[0]
        print(f"加密前:{message}")
        e_message=did_interface.encrypt(info["cpu_id"],info["disk_id"],info["product_id"],message)
        print(f"加密后:{e_message}")
        cursor.execute('''
            INSERT INTO messages (friend_id,sent, message,is_sent,timestamp,owner)
            VALUES (?, ?, ?, ?,?,?)
        ''', (friend_id,sent,e_message,is_sent,timestamp,current_id))
        #消息要加密
        conn.commit()
        conn.close()   
    # 定时补发线程
    def auto_resend_loop(self):
        while True:
            try:
                self.check_and_resend_all()
            except Exception as e:
                print("自动补发消息失败：", e)
                pass
            time.sleep(10)

    # 补发离线消息
    def check_and_resend_all(self):
        with sqlite3.connect("p2p.db", check_same_thread=False,timeout=20) as conn:

            cursor = conn.cursor()
        with sqlite3.connect("p2p.db", check_same_thread=False,timeout=20) as conn:

            cursor = conn.cursor()

            current_id=self.get_userid()
            cursor.execute("SELECT id,host FROM current_user")
            current_id_ = cursor.fetchone()[0]
            # 所有在线好友
            cursor.execute("SELECT id, ip,host_id FROM friends WHERE online = 1")
            online_friends = cursor.fetchall()

            for friend_id,host_id ,ip in online_friends:
                cursor.execute('''
                    SELECT id, message FROM messages
                    WHERE friend_id = ? AND sent = ? AND is_sent = 0 AND owner = ?
                ''', (friend_id, current_id_,current_id_))
                unsent_messages = cursor.fetchall()

                for msg_id, message in unsent_messages:
                    try:
                        # temp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                        # temp_socket.settimeout(2)
                        did_socket=DIDSocket(current_id_)
                        if host_id:
                            friend_id=host_id
                        socket_conn=did_socket.connect((friend_id,3456,ip))

                        msg_json = {
                            "sender_id": current_id_,
                            "message": message
                        }
                        did_socket.send(socket_conn,msg_json)
                        response = did_socket.recv(socket_conn)
                        print(f"[补发成功] → {friend_id}：{response}")
                        msg_json = {
                            "sender_id": current_id_,
                            "message": message
                        }
                        did_socket.send(socket_conn,msg_json)
                        response = did_socket.recv(socket_conn)
                        print(f"[补发成功] → {friend_id}：{response}")

                        cursor.execute("UPDATE messages SET is_sent = 1 WHERE id = ?", (msg_id,))
                        did_socket.close_connection(socket_conn)
                    except Exception as e:
                        print(f"[补发失败] → {friend_id}：{e}")
                        cursor.execute("UPDATE friends SET online = 0 WHERE id = ?", (friend_id,))
                        continue
            conn.commit()
            # conn.close()
    def get_userid(self):
        conn = sqlite3.connect("p2p.db", check_same_thread=False)
        cursor = conn.cursor()
        # 当前用户 ID
        cursor.execute("SELECT id,host FROM current_user")
        row = cursor.fetchone()
        current_id = row[0]
        host = row[1]
        if host:
            return current_id
        else:
            cursor.execute("select id from current_user where host=1")
            current_id=cursor.fetchone()
            current_id=current_id[0]
            return current_id
    def get_device_info(self):
        info = {
            "cpu_id": "",
            "disk_id": "",
            "product_id": ""
        }
        try:
            # 获取 CPU 序列号
            cpu_output = subprocess.check_output("wmic cpu get ProcessorId", shell=True).decode()
            info["cpu_id"] = re.findall(r"ProcessorId\s+(\w+)", cpu_output)[0].strip()

            # 获取 硬盘序列号
            # 获取硬盘序列号（修复了提取问题）
            disk_output = subprocess.check_output("wmic diskdrive get SerialNumber", shell=True).decode()
            lines = disk_output.strip().splitlines()
            serial_lines = [line.strip() for line in lines[1:] if line.strip()]
            info["disk_id"] = serial_lines[0] if serial_lines else ""
            print("Disk Output:", repr(disk_output))

            # 获取 Windows 产品 ID
            product_output = subprocess.check_output("wmic os get SerialNumber", shell=True).decode()
            info["product_id"] = re.findall(r"SerialNumber\s+(.+)", product_output)[0].strip()

        except Exception as e:
            print(f"获取设备信息失败: {e}")
        return info
if __name__ == "__main__":
    private_chat=Private_chat()
    private_chat.client("haha","did:p2p_did_chat:l3i7nMgRYu","12654565")